from soj.builtin.compare.common import ensure_file,ResultCode,CompareResult,translate_msg
from soj.settings.compare.float.float import DEFAULT_PRECISION
from pathlib import Path
from math import isinf,isnan
class FloatCompare:
    def __init__(self,file_p:Path,file_j:Path,precision_limit:int=DEFAULT_PRECISION):
        ensure_file(file_p)
        ensure_file(file_j)
        self.file_p=file_p.resolve().absolute()
        self.file_j=file_j.resolve().absolute()
        self.lim=precision_limit
    def compare(self)->CompareResult:
        try:
            with open(self.file_p) as fp:
                p_str=str(fp.read()).strip()
                p_flt=float(p_str)
        except OSError as e:
            return {
                'result_code':ResultCode.FAILED,
                'msg':"[SE:FloatCompare] Cannot open partcipant file"
            }
        except ValueError as e:
            return {
                'result_code':ResultCode.UNACCEPTABLE,
                'msg':translate_msg(f"{p_str} is not a float")
            }
        except Exception as e:
            return {
                'result_code':ResultCode.FAILED,
                'msg':'[SE:FloatCompare] Unknown exception raised'
            }
        
        try:
            with open(self.file_j) as fp:
                j_str=str(fp.read()).strip()
                j_flt=float(j_str)
        except OSError as e:
            return {
                'result_code':ResultCode.FAILED,
                'msg':"[SE:FloatCompare] Cannot open jury file"
            }
        except ValueError as e:
            return {
                'result_code':ResultCode.FAILED,
                'msg':translate_msg(f"[SE:FloatCompare] {j_str} is not a float")
            }
        except Exception as e:
            return {
                'result_code':ResultCode.FAILED,
                'msg':'[SE:FloatCompare] Unknown exception raised'
            }
        
        if isinf(p_flt) or isinf(j_flt):
            if isinf(p_flt) and isinf(j_flt):
                return {
                        'result_code':ResultCode.ACCEPTABLE,
                        'msg':'Accepted but partcipant and jury both got INF'
                    }
            elif isinf(p_flt):
                return {
                    'result_code':ResultCode.UNACCEPTABLE,
                    'msg':translate_msg('Unacctped, partcipant got INF but jury not')
                }
            elif isinf(j_flt):
                return {
                    'result_code':ResultCode.UNACCEPTABLE,
                    'msg':translate_msg('Unacctped, jury got INF but partcipant not')
                }
        
        if isnan(p_flt) or isnan(j_flt):
            if isnan(p_flt) and isnan(j_flt):
                return {
                        'result_code':ResultCode.ACCEPTABLE,
                        'msg':'Accepted but partcipant and jury both got NAN'
                    }
            elif isnan(p_flt):
                return {
                    'result_code':ResultCode.UNACCEPTABLE,
                    'msg':translate_msg('Unacctped, partcipant got NAN but jury not')
                }
            elif isnan(j_flt):
                return {
                    'result_code':ResultCode.UNACCEPTABLE,
                    'msg':translate_msg('Unacctped, jury got NAN but partcipant not')
                }

        dif=abs(p_flt-j_flt)
        tol=10.0**(-self.lim)
        if dif<tol or dif<max(abs(p_flt),abs(j_flt))*tol:
            return {
                'result_code':ResultCode.ACCEPTABLE,
                'msg':translate_msg(f'Acceptable float difference {dif}')
            }
        else:
            return {
                'result_code':ResultCode.UNACCEPTABLE,
                'msg':translate_msg(f'Too large difference {dif} / tolerance 10^(-{self.lim})')
            }